#include <stdio.h>
#include <string.h>
#include <time.h>

#include "ir.h"
#include "control.h"

static const ir_coding_t MITSABISHI_IR_CODE = {
	38,				// frequency
	50,				// duty 0 - 100
	LSB_FORMAT,	// LSB or MSB
	{ 3500,	1700 },	// start bit
	{  440,	1000 }, // stop bit
	{  440, 1300 }, // logical '1'
	{  440,	 440 }, // logical '0'
};

static const ir_coding_t GALANZ_IR_CODE = {
	38,
	50,
	LSB_FORMAT,
	{ 3800, 1400 },
	{  580, 1000 },
	{  580, 1180 },
	{  580,  450 },
};

int writeIRData(libusb_device_handle *usbdev_handle, char *str, int bits, const char sn[6]) {
	unsigned int _irCode[128];
	unsigned char irCode[128];
	char *data[128];
	int count = 0;
	int i, ret;
	
	data[0] = strtok (str,",.-|");
	//printf("data[%d]=%s\n", count, data[count]);
	
	while (data[count ++] != NULL) {
		data[count] = strtok (NULL, ",.-|");
		//printf("data[%d]=%s\n", count, data[count]);
	}
	count -= 1;
	//printf("count=%d\n", count);
	
	for(i = 0; i < count; i ++) {
		sscanf(data[i], "%x", &_irCode[i]);
		irCode[i] = _irCode[i] & 0xFF;
	}
	
	printf("write %d bytes IR data: ", count);
	for(i = 0; i < count; i ++) {
		printf("%02x", irCode[i] & 0xFF);
		if(i != (count - 1))
			printf(",");
	}
	
	if(bits < 0) {
		bits = count * 8;
	}
	
	if(sn) 
	{
		ret = rf_ctrl_cmd(usbdev_handle, U2WRQ_IR_WDATA, count, bits, (char *)irCode, count, 500, FALSE, sn);
	}
	else
	{
		ret = usb_ctrl_cmd(usbdev_handle, U2WRQ_IR_WDATA, count, bits, (char *)irCode, count, 500, FALSE);
	}
	
	if(ret != count) {
		return -1;
	}
	printf(" ... [ok]\n");
	return 0;	
}

void showBitime(const char *name, ir_bit_time_t *time) {
	printf("%s forest: %4d, plain: %d\n", name, time->forestTime, time->plainTime);
}

void toUpper(char *str) {
	while( *str != '\0' ) {
		*str = toupper(*str);
		str ++;
	}
}

int configIR(libusb_device_handle *usbdev_handle, const char *data, const char sn[6]) {
	FILE *fh;
	int i;
	char lineBuffer[512];
	char target[512];
	char *ptr[8];
	int value, ret, err = 0, count = 0;
	ir_coding_t ir_code;
	
	if(strcmp(data, "mitsabishi") == 0)
	{
		printf("Infrared standard: Mitsabishi KP06AS\n");
		memcpy(&ir_code, &MITSABISHI_IR_CODE, sizeof(ir_coding_t));
	}
	else if(strcmp(data, "galanz") == 0)
	{
		printf("Infrared standard: GALANZ GZ-50GB\n");
		memcpy(&ir_code, &GALANZ_IR_CODE, sizeof(ir_coding_t));
	}
	else
	{
		fh = fopen(data, "r");
		if (fh == NULL) 
		{
			printf("can not open IR config file: %s\n", data);
			return -1;
		}

		while (1) {
			if (fgets(lineBuffer, sizeof(lineBuffer), fh) == NULL) 
			{
				//printf("end of file!\n");
				break;
			}
			
			toUpper(lineBuffer);
			
			//printf("line:%s\n", lineBuffer);
			ptr[0] = strtok (lineBuffer, "= \n\r");
			// printf("ptr[0]=%s\n", ptr[0]);
			// this is an empty line
			if(ptr[0] == NULL) 
			{
				continue;
			}
			// this is an comment line
			if(strcmp(ptr[0], "//") == 0)
			{
				//printf("[skip]\n");
				continue;
			}
			
			count = 1;
			while ( (ptr[count] != NULL) && (count < 4) )
			{
				ptr[count ++] = strtok (NULL, "= \n\r");
				// printf("ptr[%d]=%s\n", count, ptr[count]);
				// count ++;
			}
			
			if(count >= 2) 
			{
				strcpy(target, ptr[0]);
				
				if (sscanf(ptr[1], "%d", &value) != 1) 
				{
					value = 0;
				}
				// printf("%s %d\n", target, value);
				
				if (strcmp(target, "CLK_FREQ_KHZ") == 0)
				{
					ir_code.carrierFreq = value;
					
					if( (value > 500) || (value < 1) )
					{
						printf("\'CLK_FREQ_KHZ\' must within the rang of 1-500\n");
						err = 1;
					}
				} 
				else if (strcmp(target, "CLK_DUTY_0_TO_100") == 0) 
				{
					ir_code.carrierDuty = value;
					
					if( (value > 100) || (value < 0) )
					{
						printf("\'CLK_DUTY_0_TO_100\' must within the rang of 0-100\n");
						err = 1;
					}
				} 
				else if (strcmp(target, "DATA_LSB_FORMAT") == 0) 
				{
					ir_code.dataFormat = (value ? LSB_FORMAT : MSB_FORMAT);
				} 
				else if (strcmp(target, "START_BIT_FOREST_US") == 0) 
				{
					ir_code.startBit.forestTime = value;
					
					if( (value > 65535) || (value < 0) )
					{
						printf("\'START_BIT_FOREST_US\' must within the rang of 0-65535\n");
						err = 1;
					}
				} 
				else if (strcmp(target, "START_BIT_PLAIN_US") == 0) 
				{
					ir_code.startBit.plainTime = value;
					
					if( (value > 65535) || (value < 0) )
					{
						printf("\'START_BIT_PLAIN_US\' must within the rang of 0-65535\n");
						err = 1;
					}
				}
				else if (strcmp(target, "STOP_BIT_FOREST_US") == 0)
				{
					ir_code.stopBit.forestTime = value;
					
					if( (value > 65535) || (value < 0) )
					{
						printf("\'STOP_BIT_FOREST_US\' must within the rang of 0-65535\n");
						err = 1;
					}
				}
				else if (strcmp(target, "STOP_BIT_PLAIN_US") == 0)
				{
					ir_code.stopBit.plainTime = value;
					
					if( (value > 65535) || (value < 0) )
					{
						printf("\'STOP_BIT_PLAIN_US\' must within the rang of 0-65535\n");
						err = 1;
					}
				}
				else if (strcmp(target, "LOGICAL_1_FOREST_US") == 0) 
				{
					ir_code.logicalBit1.forestTime = value;
					
					if( (value > 65535) || (value < 0) )
					{
						printf("\'LOGICAL_1_FOREST_US\' must within the rang of 0-65535\n");
						err = 1;
					}
				}
				else if (strcmp(target, "LOGICAL_1_PLAIN_US") == 0) 
				{
					ir_code.logicalBit1.plainTime = value;
					
					if( (value > 65535) || (value < 0) )
					{
						printf("\'LOGICAL_1_PLAIN_US\' must within the rang of 0-65535\n");
						err = 1;
					}
				}
				else if (strcmp(target, "LOGICAL_0_FOREST_US") == 0) 
				{
					ir_code.logicalBit0.forestTime = value;
					
					if( (value > 65535) || (value < 0) )
					{
						printf("\'LOGICAL_0_FOREST_US\' must within the rang of 0-65535\n");
						err = 1;
					}
				}
				else if (strcmp(target, "LOGICAL_0_PLAIN_US") == 0) 
				{
					ir_code.logicalBit0.plainTime = value;
					
					if( (value > 65535) || (value < 0) )
					{
						printf("\'LOGICAL_0_PLAIN_US\' must within the rang of 0-65535\n");
						err = 1;
					}
				} 
				else if (strcmp(target, "INFRARED_STANDARD") == 0)
				{
					printf("Infrared standard: ");
					if (ptr[1]) 
					{
						printf("%s", ptr[1]);
					}
					printf("\n");
				} 
				else {
					// printf("unrecognized option ‘%s'\n", target);  
				}
			}
			if (err) 
			{
				break;
			}
		} // while (1)
		
		fclose(fh);
	}
#if (1)
	if (err == 0) 
	{
		printf("--------------------------------------------------\n");
		printf("carrier frequency khz: %d, ", ir_code.carrierFreq);
		printf("duty: %d, ", ir_code.carrierDuty);
		printf("%s\n", (ir_code.dataFormat == LSB_FORMAT) ? "LSB format" : "MSB format");
		showBitime("start bit", &ir_code.startBit);
		showBitime(" stop bit", &ir_code.stopBit);
		showBitime("  \'1\' bit", &ir_code.logicalBit1);
		showBitime("  \'0\' bit", &ir_code.logicalBit0);
		printf("--------------------------------------------------\n");
	}
#endif
	
	if (err == 0) 
	{
		if (sn)
		{
			ret = rf_ctrl_cmd(usbdev_handle, U2WRQ_IR_CONFIG, sizeof(ir_coding_t), sizeof(ir_coding_t), (char *)&ir_code, sizeof(ir_coding_t), 500, FALSE, sn);
		}
		else
		{
			ret = usb_ctrl_cmd(usbdev_handle, U2WRQ_IR_CONFIG, sizeof(ir_coding_t), sizeof(ir_coding_t), (char *)&ir_code, sizeof(ir_coding_t), 500, FALSE);
		}
		if(ret != sizeof(ir_coding_t)) 
		{
			printf("config IR error\n");
			return -1;
		}
		printf("config IR ok\n");
		return 0;
	}
	else 
	{
		return -1;
	}
}

unsigned char uint8CheckSum(unsigned char *buffer, int len) {
	unsigned char sum = 0;
	int i;
	
	for(i = 0; i < len; i ++) {
		sum += buffer[i];
	}
	return sum;
}

int writeACCode(libusb_device_handle *usbdev_handle, int isTurnOn, int isColdMode, int temperature, const char sn[6]) {
	unsigned char mitsubishiAcCodeSample[18] = {
		0x23,0xcb,0x26,0x01,0x00,0x20,0x58,0x0a,0x06,0x50,0x3b,0x00,0x00,0x80,0x10,0x00,0x00,0xb8};
	unsigned char packages[40];
	
	int ret, i;
	//int hour, min;
	time_t now;
	struct tm *t;
	
	now = time(NULL);
	t = localtime(&now);
	
	configIR(usbdev_handle, "mitsabishi", sn);
	
	printf("Turn %s AC in %s mode, temp is %d degree, time is %02d:%02d ... ", isTurnOn ? "ON" : "OFF",
		isColdMode ? "COLD" : "HOT", temperature, t->tm_hour, t->tm_min);
	
	//printf("hour = %d, min = %d\n", t->tm_hour, t->tm_min);
	//printf("%s", ctime(&now));	
	
	// set power code
	if(isTurnOn) {
		mitsubishiAcCodeSample[5] = 0x20;
	} else {
		mitsubishiAcCodeSample[5] = 0x00;
	}
	// set HOT/COLD mode
	if(isColdMode) {
		mitsubishiAcCodeSample[6] = 0x58;
	} else {
		mitsubishiAcCodeSample[6] = 0x48;
	}
	// set temperature
	mitsubishiAcCodeSample[7] = temperature - 16;
	
	// set time value
	mitsubishiAcCodeSample[10] = t->tm_hour * 6 + t->tm_min / 10;
	
	// check sum
	mitsubishiAcCodeSample[17] = uint8CheckSum(mitsubishiAcCodeSample, 17);
	
	// total bist
	packages[0] = 18 * 8; 
	// delay time ms
	packages[1] = 15;
	// second package, same data     
	packages[20] = 18 * 8;
	packages[21] = 1;
	
	memcpy(&packages[2], mitsubishiAcCodeSample, sizeof(mitsubishiAcCodeSample));
	memcpy(&packages[22], mitsubishiAcCodeSample, sizeof(mitsubishiAcCodeSample));
	
	if (sn)
	{
		ret = rf_ctrl_cmd(usbdev_handle, U2WRQ_IR_WDATA, 40, 40, packages, 40, 500, FALSE, sn);
	}
	else 
	{
		ret = usb_ctrl_cmd(usbdev_handle, U2WRQ_IR_WDATA, 40, 40, packages, 40, 500, FALSE);
	}
	if(ret != 40) {
		printf("[error]\n");
		return -1;
	}
	printf("[ok]\n");
	return 0;
}

